﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

#pragma once

#include "GcmpModelInterface.h"
#include "IType.h"
#include "UniIdentity.h"

namespace gcmp {  

    class IGroupEvent;

    /// \brief 组类型接口
    class GCMP_MODEL_INTERFACE_EXPORT IGroupType : public IType
    {
        DEFINE_CAST_DERIVED(gcmp::IGroupType, gcmp::IType);
    public:
        /// \brief 创建组类型，对指定的elements进行拷贝操作，将拷贝后的elements放入组类型内
        /// \param pDocument[in] 组类型所属的文档指针
        /// \param pModelView[in] 视图指针，用于计算构件包围盒
        /// \param typeName[in] 组类型名称
        /// \param elementIds[in] 指定的element集合
        /// \return IGroupType* 组类型对象指针，失败时返回nullptr
        static IGroupType* Create(IDocument* pDocument, const IModelView* pModelView, const std::wstring& typeName, const UnorderedElementIdSet& elementIds);

        /// \brief 创建组类型，将指定的elements直接放入组类型内，不进行拷贝操作
        /// \param pDocument[in] 组类型所属的文档指针
        /// \param pModelView[in] 视图指针，用于计算构件包围盒
        /// \param typeName[in] 组类型名称
        /// \param elementIds[in] 指定的element集合
        /// \return IGroupType* 组类型对象指针，失败时返回nullptr
        static IGroupType* CreateWithoutCopy(IDocument* pDocument, const IModelView* pModelView, const std::wstring& typeName, const UnorderedElementIdSet& elementIds);

        /// \brief 获取组内元素拷贝的事件
        /// \return 返回组内元素拷贝的事件，如果用户需要在元素拷贝前后做一些特殊处理，可添加handler
        static IGroupEvent* GetGroupEvent();

        /// \brief 获得所有组类型
        /// 
        /// \param pDocument 文档指针
        /// \return 组类型集合
        static std::vector<IGroupType*> GetAllGroupTypes(const IDocument* pDocument);

        /// \brief 获取组中所有元素的Id
        ///
        /// \return 所有元素的Id
        virtual const std::set<ElementId>& GetElementIdsInGroupType() const = 0;

        /// \brief 获取所有的组
        /// \param groupIds 输出参数，该组类型下所有组实例的ElementId（不包括嵌套组组类型内的Group的ElementId）
        /// \return 获取成功返回true，发生异常返回false
        virtual bool GetAllGroupIds(std::set<ElementId>& groupIds) const= 0;

        /// \brief 获取组类型中element的个数
        /// \return 返回组类型内包含的element的个数
        virtual size_t GetElementsCountInGroupType() const = 0;

        /// \brief 向组中添加辅助元素
        /// \param assistElementId 辅助元素ElementId
        /// \return
        virtual void AddAssistElementToGroupType(const ElementId& assistElementId) = 0;

        /// \brief 从组中删除辅助元素
        /// \param assistElementId 辅助元素ElementId
        /// \return
        virtual void DeleteAssistElementFromGroupType(const ElementId& assistElementId) = 0;

        /// \brief 获取组中所有辅助元素的Id
        ///
        /// \return 所有元素的Id
        virtual const std::set<ElementId>& GetAssistElementIdsInGroupType() const = 0;

        /// \brief 添加引用对象，该对象不属于组也不随组联动，只是它的修改可以同步至组类型和其他组实例
        /// \param elementId 要添加引用的元素的ElementId
        /// \return 添加成功返回true，否则返回false。如果返回false，需要执行事务的rollBack操作
        /// \note 该元素必须是组内第一层子组内的元素，否则添加失败
        virtual bool AddReferenceElement(const ElementId& elementId) = 0;

        /// \brief 删除引用对象，该修改会同步至组类型和其他组实例
        /// \param elementId 要删除引用的元素的ElementId
        /// \return 删除成功返回true，否则返回false
        virtual void RemoveReferenceElement(const ElementId& elementId) = 0;

        /// \brief 获取组中所有引用元素的Id
        ///
        /// \return 所有元素的Id
        virtual const std::set<ElementId>& GetReferenceElementIdsInGroupType() const = 0;

        /// \brief 添加对象到组类型
        /// \param elementId 要添加的元素的ElementId
        /// \return 如果组类型已存在组实例则添加失败返回false，否则返回true
        virtual bool AddElementWhenHasNoGroupInstances(const ElementId& elementId) = 0;

        /// \brief 将组类型内的对象移除出组
        /// \param elementId 要移除元素的ElementId
        /// \return 如果组类型已存在组实例则移除失败返回false，否则返回true
        virtual bool RemoveElementWhenHasNoGroupInstances(const ElementId& elementId) = 0;

        /// \brief 从组类型中删除指定的Element
        /// \param elementId 要删除的元素的ElementId
        /// \return 如果组类型已存在组实例则删除失败返回false，否则返回true
        virtual bool DeleteElementWhenHasNoGroupInstances(const ElementId& elementId) = 0;

        /// \brief 从组类型中添加指定的Element，并记录改变类型，后面用于同步
        /// \param elementId 要添加的元素的ElementId
        /// \return 如果组类型添加Element失败返回false，否则返回true
        virtual bool AddElement(const ElementId& elementId) = 0;

        /// \brief 从组类型中删除指定的Element，并记录改变类型，后面用于同步
        /// \param elementId 要删除的元素的ElementId
        /// \return 如果组类型删除Element失败返回false，否则返回true
        virtual bool DeleteElement(const ElementId& elementId) = 0;

        /// \brief 从组类型中移除指定的Element，并记录改变类型，后面用于同步
        /// \param elementId 要移除的元素的ElementId
        /// \return 如果组类型移除Element失败返回false，否则返回true
        virtual bool RemoveElement(const ElementId& elementId) = 0;

        /// \brief 从组类型中改变指定的Element，并记录改变类型，后面用于同步
        /// \param elementId 要改变的元素的ElementId
        /// \return 如果组类型改变Element失败返回false，否则返回true
        virtual bool ChangeElement(const ElementId& elementId) = 0;

        /// \brief 从组类型中恢复RefElement，并记录改变类型，后面用于同步,外面保证elementId代表的Element已经创建并在正确的位置
        /// \param elementId 要恢复的ref元素的ElementId
        /// \param groupId 要恢复到的类型中的group的Id
        /// \param elementId 原grouptype中同位元素的ElementId
        /// \return 失败返回false，否则返回true
        virtual bool RestoreRefrenceElement(const ElementId& elementId, const ElementId& addToGroupId, const ElementId& originElementId) = 0;

        /// \brief 从组类型同步到组实例
        /// \param bSortElementChangeData 是否在同步之前对element按依赖关系排序,true表示排序;
        /// \return 如果同步失败返回false，否则返回true
        virtual bool SyncToGroups(bool bSortElementChangeData) = 0;

        virtual ~IGroupType() {}

#pragma region ObsoleteAPI
        /// \brief 创建组类型，对指定的elements进行拷贝操作，将拷贝后的elements放入组类型内
        /// \param pDocument[in] 组类型所属的文档指针
        /// \param pModelView[in] 视图指针，用于计算构件包围盒
        /// \param typeName[in] 组类型名称
        /// \param elementIds[in] 指定的element集合
        /// \param errorMsg[out] 返回创建组类型的错误信息，如果用户不想获取具体的错误信息，可设为nullptr
        /// \return IGroupType* 组类型对象指针，失败时返回nullptr
        GCMP_OBSOLETE_API(2021 / 09 / 01, IGroupType::Create(IDocument*, const IModelView*, const std::wstring&, const UnorderedElementIdSet&)) static IGroupType* Create(IDocument* pDocument, const IModelView* pModelView, const std::wstring& typeName, const UnorderedElementIdSet& elementIds, std::wstring* errorMsg);

        /// \brief 创建组类型，将指定的elements直接放入组类型内，不进行拷贝操作
        /// \param pDocument[in] 组类型所属的文档指针
        /// \param pModelView[in] 视图指针，用于计算构件包围盒
        /// \param typeName[in] 组类型名称
        /// \param elementIds[in] 指定的element集合
        /// \param errorMsg[out] 返回创建组类型的错误信息，如果用户不想获取具体的错误信息，可设为nullptr
        /// \return IGroupType* 组类型对象指针，失败时返回nullptr
        GCMP_OBSOLETE_API(2021 / 09 / 01, IGroupType::CreateWithoutCopy(IDocument*, const IModelView*, const std::wstring&, const UnorderedElementIdSet&)) static IGroupType* CreateWithoutCopy(IDocument* pDocument, const IModelView* pModelView, const std::wstring& typeName, const UnorderedElementIdSet& elementIds, std::wstring* errorMsg);

#pragma endregion ObsoleteAPI
    };
}// namespace gcmp
